<?php

defined('BASEPATH') or die('forbidden');
/**
 * 框架核心类
 * @author  Karson
 * @name    framework.php
 * @since   2013-6-3 21:10:48
 */
//设置超时时间
set_time_limit(3);
//设置内存最多使用限制
ini_set('memory_limit', '128M');
//初始执行时间
define('START_TIME', microtime(true));
define('TIME', ceil(START_TIME * 1000));
//初始内存使用量
define('START_MEMORY_USAGE', memory_get_usage());

include BASEPATH . 'framework/base.php';
include APPPATH . 'configs/constant.php';

//框架实例化
$framework = new Framework();

$framework->run();
log_message("End[----------]\n");

//框架核心类
class Framework {

    var $config = null;
    var $controller = null;
    var $controller_name = null;
    var $controller_file = null;
    var $action = null;
    var $action_name = null;
    var $path_info = null;
    var $truepath_info = null;
    var $url_segment = null;
    var $is_foler = 0;
    var $params = null;
    var $hooks;

    //使用单例模式运行
    public function __construct($tag = 'default') {
        self::instance($tag, $this);
    }

    //静态单例模式
    public static function &instance($tag = 'default', $new = null) {
        static $instance = array();
        if (isset($new) && is_object($new))
            $instance[$tag] = $new;
        return $instance[$tag];
    }

    //框架执行入口
    public function run() {
        //钩子初始化对象
        $this->hooks();

        //读取PATH_INFO
        $this->path_info = !empty($_SERVER['PATH_INFO']) ? str_replace('index.php', '', $_SERVER['PATH_INFO']) : '';

        //包含配置文件并获取配置信息
        $this->config();

        //加载区域语言配置
        $this->language();
        //$this->locale();
        //PATH_INFO路由替换
        $this->routing();

        //URL分段处理
        $this->segment();

        //获取控制器并实例化控制器
        $this->get_controller();

        //获取请求的方法
        $this->get_action();

        //注册控制器
        $this->call_controller();

        //自动加载需要处理的库或类
        $this->autoloader();

        //调用方法
        $this->call_action();

        //注册到钩子
        $this->hooks->call_hook("after_system");
    }

    //初始化钩子事件
    function hooks() {
        //加载钩子
        $this->hooks = & load_class('hooks');
        //注册到钩子
        $this->hooks->call_hook("before_system");
    }

    //基本配置文件处理
    public function config() {
        include APPPATH . 'configs/config.php';
        if (!isset($config) || !is_array($config))
            throw new Exception('配置文件内容必须是一个数组！');
        $this->config = $config;
        //设置时区
        ini_set('date.timezone', $config['timezone']);
    }

    //采用数组配置语言
    public function language() {
        $appname = basename(dirname($_SERVER['SCRIPT_NAME']));
        $appname = $appname ? $appname : 'application';
        $langfile = 'languages/' . (isset($this->config['languages'][$appname]) ? $this->config['languages'][$appname] : '') . '.php';
        global $lang;
        if (file_exists(APPPATH . $langfile)) {
            include APPPATH . $langfile;
        } else {
            if (file_exists(BASEPATH . $langfile)) {
                include BASEPATH . $langfile;
            }
        }
    }

    //采用gettext配置语言
    public function locale() {
        //从COOKIE中获取语言包,如果不存在则从浏览器中获取
        $locale = isset($_COOKIE['lang']) ? $_COOKIE['lang'] : Locale::acceptFromHttp(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : 'zh_CN');
        $locale = in_array($locale, $this->config['languages']) ? $locale : $this->config['languages'][0];
        putenv("LC_ALL={$locale}");
        setlocale(LC_ALL, $locale);
        bindtextdomain("default", BASEPATH . 'locale/');
        textdomain("default");
        bind_textdomain_codeset("default", "utf-8");
    }

    //PATH_INFO路由替换
    public function routing() {
        $this->truepath_info = $this->path_info;
        if (!empty($this->config['url_search']) && !empty($this->config['url_replace']))
            $this->truepath_info = preg_replace($this->config['url_search'], $this->config['url_replace'], $this->path_info);
    }

    //PATH_INFO分段处理
    public function segment() {
        $this->url_segment = (!empty($this->truepath_info)) ? array_filter(explode('/', trim($this->truepath_info, '/'))) : null;
        //$this->params = is_array($this->url_segment) && count($this->url_segment) > 2 ? array_slice($this->url_segment,2) : null;
    }

    //获取控制器并实例化对象
    public function get_controller() {
        if (!empty($this->config['root_controller'])) {
            $controller_name = $this->config['root_controller'];
            $controller_file = APPPATH . 'controllers/' . $controller_name . '.php';
        } else {
            $name = (!empty($this->url_segment[0])) ? $this->url_segment[0] : $this->config['default_controller'];
            $cname = (!empty($this->url_segment[1])) ? $this->url_segment[1] : $this->config['default_controller'];
            if (is_dir(APPPATH . 'controllers/' . $name) && is_file(APPPATH . 'controllers/' . $name . '/' . $cname . '.php')) {
                $controller_name = $cname;
                $controller_file = APPPATH . 'controllers/' . $name . '/' . $cname . '.php';
                $this->is_folder = 1;
            } else {
                if (!is_file(APPPATH . 'controllers/' . $name . '.php')) {
                    show_404($this->path_info);
                    $controller_name = 'index';
                    $controller_file = APPPATH . 'controllers/index.php';
                } else {
                    $controller_name = $name;
                    $controller_file = APPPATH . 'controllers/' . $name . '.php';
                }
                $this->is_folder = 0;
            }
        }
        $this->controller_name = $controller_name;
        $this->controller_file = $controller_file;
    }

    //获取请求的方法
    public function get_action() {
        if (!empty($this->config['rootget_action'])) {
            $this->action = $this->config['root_action'];
        } else {
            $this->action = (!empty($this->url_segment[$this->is_folder + 1])) ? $this->url_segment[$this->is_folder + 1] :
                    (!empty($this->config['default_action']) ? $this->config['default_action'] : 'index');
            //if (substr($this->action, 0, 1) == '_' || !in_array($this->action, get_class_methods($this->controller)))
            $this->action = $this->action == 'list' ? 'lists' : $this->action;
            if (substr($this->action, 0, 1) == '_')
                throw new Exception("方法[{$this->action}]未找到或不允许请求");
        }
        $this->action_name = $this->action;
        $this->params = is_array($this->url_segment) && count($this->url_segment) > (2 + $this->is_folder) ? array_slice($this->url_segment, (2 + $this->is_folder)) : null;
    }

    function call_controller() {
        //注册到钩子
        $this->hooks->call_hook("before_controller");
        //加载文件
        include_once $this->controller_file;

        //获取类名并实例化对象
        $class_name = ucfirst($this->controller_name) . '_Controller';
        $this->controller = new $class_name(true);
        $this->controller->hooks = & $this->hooks;
    }

    function call_action() {
        //注册到钩子
        $this->hooks->call_hook("before_controller_function");
        //初始化方法
        if (method_exists($this->controller, "_init"))
            $this->controller->_init();

        //执行请求的方法;
        if (is_array($this->params) && count($this->params) > 0) {
            call_user_func_array(array(&$this->controller, $this->action), $this->params);
        } else {
            $this->controller->{$this->action}();
        }
    }

    //处理需要自动加载的库和类
    public function autoloader() {
        include APPPATH . 'configs/autoload.php';
        if (!empty($config['configs'])) {
            foreach ($config['configs'] as $key => $value) {
                if (is_numeric($key))
                    $this->controller->load->config($value);
                else
                    $this->controller->load->config($key, $value);
            }
        }
        if (!empty($config['database'])) {
            foreach ($config['database'] as $key => $value) {
                if (is_numeric($key))
                    $this->controller->load->database($value);
                else
                    $this->controller->load->database($key, $value);
            }
        }
        if (!empty($config['helpers'])) {
            foreach ($config['helpers'] as $helper)
                $this->controller->load->helper($helper);
        }

        if (!empty($config['libraries'])) {
            foreach ($config['libraries'] as $key => $value) {
                if (is_numeric($key))
                    $this->controller->load->library($value);
                else
                    $this->controller->load->library($key, $value);
            }
        }
        if (!empty($config['models'])) {
            foreach ($config['models'] as $key => $value) {
                if (is_numeric($key))
                    $this->controller->load->model($value);
                else
                    $this->controller->load->model($key, $value);
            }
        }
    }

}